package com.neusoft.hifly.security;

import java.util.HashMap;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;

/**
 * Title: Kernel Library
 * <p>
 * Description: 加密解密字符串、Byte数组工具类
 * <p>
 * Copyright: 2019
 * <p>
 * Company: 东软汉枫
 *
 * @author lh_neu
 * @version 1.0.0
 */
public class DataEncryption {

	private static final int MD5_LEN = 32;

	public static final String DEFAULT_KEY = "ChinaCTDataEncryption";

	/**
	 * 密码加密
	 *
	 * @param key
	 *            秘钥
	 * @param pwd
	 *            密码
	 * @return 加密后的串
	 */
	public static String encodePassword(final String key, final String pwd) {
		if (StringUtils.isNotEmpty(pwd)) {
			return EncodeUtils.md5Encode(StringUtils.trimToEmpty(pwd + key));
		} else {
			return "";
		}
	}

	/**
	 * 密码加密
	 *
	 * @param key
	 *            秘钥
	 * @param pwd
	 *            密码
	 * @return 加密后的串
	 */
	public static String encodePassword(final long key, final String pwd) {
		if (StringUtils.isNotEmpty(pwd)) {
			return EncodeUtils.md5Encode(StringUtils.trimToEmpty(pwd + key));
		} else {
			return "";
		}
	}

	/**
	 * 校验密码是否正确
	 * <p>
	 * 支持两种秘密加密方式，适应老数据
	 *
	 * @param key
	 *            秘钥
	 * @param pwd
	 *            密码(明文)
	 * @param targetPwd
	 *            密码(加密后的)
	 * @return 加密后的串
	 */
	public static boolean checkPassword(final String key, final String pwd, final String targetPwd) {
		if (StringUtils.isEmpty(pwd) || StringUtils.isEmpty(targetPwd)) {
			return false;
		}
		if (targetPwd.equals(DataEncryption.encodePassword(key, pwd))
				|| targetPwd.equals(DataEncryption.encodePassword("", pwd))) {
			return true;
		}
		return false;
	}

	/**
	 * 校验密码是否正确
	 * <p>
	 * 支持两种秘密加密方式，适应老数据
	 *
	 * @param key
	 *            秘钥
	 * @param pwd
	 *            密码(明文)
	 * @param targetPwd
	 *            密码(加密后的)
	 * @return 加密后的串
	 */
	public static boolean checkPassword(final long key, final String pwd, final String targetPwd) {
		if (StringUtils.isEmpty(pwd) || StringUtils.isEmpty(targetPwd)) {
			return false;
		}
		if (targetPwd.equals(DataEncryption.encodePassword(key + "", pwd))
				|| targetPwd.equals(DataEncryption.encodePassword("", pwd))) {
			return true;
		}
		return false;
	}

	/**
	 * 深度密码加密
	 *
	 * @param key
	 *            秘钥
	 * @param pwd
	 *            密码
	 * @return 加密后的串
	 */
	public static String encodeHighPassword(final String key, final String pwd) {
		if (StringUtils.isNotEmpty(pwd)) {
			return EncodeUtils.md5Encode(EncodeUtils.md5Encode(StringUtils.trimToEmpty(pwd + key)));
		} else {
			return "";
		}
	}

	/**
	 * 校验深度密码是否正确
	 * <p>
	 * 支持两种秘密加密方式，适应老数据
	 *
	 * @param key
	 *            秘钥
	 * @param pwd
	 *            密码(明文)
	 * @param targetPwd
	 *            密码(加密后的)
	 * @return 加密后的串
	 */
	public static boolean checkHighPassword(final String key, final String pwd, final String targetPwd) {
		if (StringUtils.isEmpty(pwd) || StringUtils.isEmpty(targetPwd)) {
			return false;
		}
		if (targetPwd.equals(DataEncryption.encodeHighPassword(key, pwd))
				|| targetPwd.equals(DataEncryption.encodeHighPassword("", pwd))) {
			return true;
		}
		return false;
	}

	/**
	 * 加密字符串
	 *
	 * @param priKey
	 *            密钥
	 * @param str
	 *            需加密的字符串
	 * @param encode
	 *            字符集
	 * @return 加密后的字符串
	 */
	public static String encrypt(final String priKey, final String str, String encode) {
		if (StringUtils.isEmpty(str) || StringUtils.isEmpty(priKey)) {
			return "";
		}
		if (StringUtils.isEmpty(encode)) {
			encode = "UTF-8";
		}
		return AESCoder.encrypt(str, priKey, encode);
	}

	/**
	 * 加密字符串
	 *
	 * @param priKey
	 *            密钥
	 * @param str
	 *            需加密的字符串
	 * @param encode
	 *            字符集
	 * @return 加密后的字符串
	 */
	public static String encrypt(final String priKey, final String str) {
		if (StringUtils.isEmpty(str) || StringUtils.isEmpty(priKey)) {
			return "";
		}
		return AESCoder.encrypt(str, priKey);
	}

	/**
	 * 解密字符串
	 *
	 * @param priKey
	 *            密钥
	 * @param str
	 *            需解密的字符串
	 * @return 解密后的字符串
	 */
	public static String decrypt(final String priKey, final String str) {
		if (StringUtils.isEmpty(str) || StringUtils.isEmpty(priKey)) {
			return "";
		}
		return AESCoder.decrypt(str, priKey);
	}

	/**
	 * 校验参数串是否被修改
	 *
	 * @param paramStr
	 *            参数串
	 * @param shareCode
	 *            共享码，可以为null
	 * @return 是否被修改：未修改true、修改false
	 */
	public static boolean validate(final String paramStr, final String shareCode) {
		String md5Str = null;
		String md5 = null;
		String base64Str = null;
		if (StringUtils.isNotBlank(paramStr)) {
			md5 = DataEncryption.getMD5Str(paramStr);
			base64Str = DataEncryption.getBase64Parameter(paramStr);
			md5Str = EncodeUtils.encode(DataEncryption.enReplaceStr(base64Str), shareCode);
			return md5.equals(md5Str);
		}
		return false;
	}

	/**
	 * 获取客户端参数串中Base64部分信息
	 *
	 * @param paramStr
	 *            客户端参数串
	 * @return Base64部分信息
	 */
	public static String getBase64Parameter(final String paramStr) {
		if (StringUtils.isNotEmpty(paramStr) && paramStr.length() > DataEncryption.MD5_LEN) {
			return paramStr.substring(0, paramStr.length() - DataEncryption.MD5_LEN);
		} else {
			return "";
		}
	}

	/**
	 * 【加密】参数串
	 *
	 * @param parameter
	 *            转换前的参数
	 * @param shareCode
	 *            共享码
	 * @param encode
	 *            字符编码
	 * @return 加密后的参数串
	 */
	public static String makeParamStr(final String parameter, final String shareCode, final String encode) {
		if (StringUtils.isEmpty(parameter)) {
			return "";
		}
		final String paramsBase64 = EncodeUtils.encodeBase64Str(parameter, encode);
		final String md5Str = EncodeUtils.encode(paramsBase64, shareCode);
		return DataEncryption.replaceStr(paramsBase64 + md5Str);
	}

	/**
	 * 【解密】参数串
	 * <p>
	 * 1、校验参数串是否被修改：
	 * <p>
	 *  截取字符串后32位作为MD5字符串str1，其余部分为BASE64字符串str2；
	 * <p>
	 *  替换str2串中“%2B”的内容为“+”号，形成新的str2字符串；
	 * <p>
	 * 将str2与接口同步设置的交换密码（若没设置交换密码，则使用交换用户名）拼接在以前，形成str3字符串（strs = str2 + 交换密码）；
	 * <p>
	 *  再将str3字符串使用MD5算法加密与str1字符串比较，若相同则说明数据是合法的，若不同，则说明数据在交换过程中被篡改过，抛出异常提示。
	 * <p>
	 * 2、解密参数：
	 * <p>
	 *  将str2字符串采用BASE64解密方式进行解密即可获取加密前的参数。
	 *
	 * @param paramStr
	 *            原始参数串
	 * @param shareCode
	 *            共享码
	 * @param encode
	 *            字符编码
	 * @return 解析后的参数串
	 */
	public static String getParameter(final String paramStr, final String shareCode, final String encode) {
		if (DataEncryption.validate(paramStr, shareCode)) {
			return EncodeUtils.decodeBase64Str(DataEncryption.enReplaceStr(DataEncryption.getBase64Parameter(paramStr)),
					encode);
		} else {
			return "";
		}
	}

	/**
	 * 从参数串中解析各个参数信息
	 *
	 * @param paramStr
	 *            参数串
	 * @param shareCode
	 *            共享码
	 * @param encode
	 *            字符编码
	 * @return 解析后的参数
	 */
	public static Map<String, String> getParameterMap(final String paramStr, final String shareCode,
			final String encode) {
		String parameter = null;
		final Map<String, String> ret = new HashMap<String, String>();
		if (DataEncryption.validate(paramStr, shareCode)) {
			parameter = EncodeUtils
					.decodeBase64Str(DataEncryption.enReplaceStr(DataEncryption.getBase64Parameter(paramStr)), encode);
			final String[] parameters = parameter.split("&");
			for (final String p : parameters) {
				final String[] s = p.split("=");
				if ((s != null) && (s.length >= 2)) {
					ret.put(s[0], s[1]);
				}
			}
		}
		System.out.println(ret);
		return ret;
	}

	/**
	 * 获取MD5加密的那部分
	 *
	 * @param paramStr
	 *            加密前字符串
	 * @return MD5加密的那部分
	 */
	public static String getMD5Str(final String paramStr) {
		if (StringUtils.isNotEmpty(paramStr) && paramStr.length() > DataEncryption.MD5_LEN) {
			return paramStr.substring(paramStr.length() - DataEncryption.MD5_LEN);
		} else {
			return "";
		}
	}

	/**
	 * TODO 解决URL传递参数BASE64中+号变空格的问题 2010.06.21 Charles
	 *
	 * @author lh_neu
	 * @date 2010.06.21
	 * @param result
	 *            字符串
	 * @return 替换后的字符串
	 */
	private static String replaceStr(String result) {
		if (StringUtils.isNotEmpty(result) && (result.indexOf("+") >= 0)) {
			result = result.replaceAll("\\+", "%2B");
		}
		return result;
	}

	/**
	 * 替换str2串中“%2B”的内容为“+”号
	 *
	 * @param result
	 *            字符串
	 * @return 替换后的字符串
	 */
	private static String enReplaceStr(String result) {
		if (StringUtils.isNotEmpty(result) && (result.indexOf("%2B") >= 0)) {
			result = result.replaceAll("%2B", "\\+");
		}
		return result;
	}

	/**
	 * 测试主函数
	 *
	 * @param args
	 *            参数
	 */
	public static void main(final String[] args) {
		//		System.out.println("df2abb1b54502d065a149d5e25849844".length());
		//		System.out.println(DataEncryption.encodePassword("139573089415151", "123456"));
		//		System.out.println(DataEncryption.encodeHighPassword("139573089415151", "123456"));

		// http://localhost:8080/CTSaaS/report/test.html?tenantCode=qch&loginName=Z3Vlc3Q=5cca43e7c6e175241496fb92775a4cee&password=MTIzNDU2f50c1fcdd872c8e502ac868d8d9ac400
		System.out.println(DataEncryption.makeParamStr("username", "shareCode", "UTF-8"));
		System.out.println(
				DataEncryption.getParameter("dXNlcm5hbWU=fce7e14ce759b4ba2cd615125ac5c13c", "shareCode", "UTF-8"));
		//		System.out.println(DataEncryption.getParameterMap("VEVTVA==2b7e5d118a642c0e689f8827a48528fe", "shareCode", "UTF-8"));

		//		System.out.println(DataEncryption.encodePassword("", "1"));
		//		String str = "k=122313&u=qqqq&p=123456";
		//		String a = DataEncryption.makeParamStr(str, "shareCode", "UTF-8");
		//		System.out.println(a);
		//		System.out.println(DataEncryption.getParameter(a, "shareCode", "UTF-8"));
		//
		//		Map<String, String> map = DataEncryption.getParameterMap(a, "shareCode", "UTF-8");
		//
		//		final Iterator<Map.Entry<String, String>> iter = map.entrySet().iterator();
		//		while (iter.hasNext()) {
		//			final Map.Entry<String, String> entry = iter.next();
		//			final String key = entry.getKey();
		//			final String val = entry.getValue();
		//			System.out.println(key + " -> " + val);
		//		}

		//		System.out.println(DataEncryption.encodePassword("139573089415151", "1"));
		//		//		加密前的字符：Hellow Word!
		//		//		加密后的字符：6b189a916ce2477fd55dd80903836156
		//		//		解密后的字符：Hellow Word!
		//
		//		try {
		//			final String test = "加密解密字符串、Byte数组工具类Hellow Word!This is a organ key.";
		//			System.out.println("加密前的字符：" + test);
		//			System.out.println("加密后的字符：" + DataEncryption.encrypt("12345678", test, "UTF-8"));
		//			System.out.println("解密后的字符：" + DataEncryption.decrypt("12345678", DataEncryption.encrypt("12345678", test, "UTF-8")));
		//
		//			final String str = "SELECT model.ID id, model.NAME name, model.STATUS status, model.ACT_INST_ID actInstId, model.ORIGEN_PERFORMER_ID origenPerformerId, model.PERFORMER_ID performerId, model.CREATE_DATE createDate, model.LAST_UPDATE_DATE lastUpdateDate, model.PRIORITY priority, model.TYPE type, model.ITEM_NAME itemName, model.POINTER pointer, model.ITEM_STATUS itemStatus, model.APPLINK appLink, model.PERSONFLAG personFlag, model.APPROVE_TIME approveTime, model.PROCESS_INST_ID processInstId, model.PROCESS_NAME processName, model.STEP_ID stepId,CONCAT(\"<a href=<%=basePath%>/app/approveAction.xhtml?formLogicId=bb9411d5a90841ec93a791d8099748f7&objLogicId=\",modlog.REPORT_ID,\">打开</a>\") 操作 FROM CSJGZXTX_baoxiao_WORKITEM model,CSJGZXTX_baoxiao_operalog modlog WHERE 1=1 AND modlog.WORKITEM_ID=model.ID AND model.STATUS in(\"ready\") AND model.PERFORMER_ID =\"131434009779644\" AND model.ACT_INST_ID in (SELECT actInst.ID FROM CSJGZXTX_ACTIVITY_INSTANCE actInst WHERE  actInst.STATUS not in (\"finish\",\"exception\")) AND  model.STATUS <> \"reject\"  ORDER BY model.PRIORITY DESC, model.CREATE_DATE DESC";
		//			final String encode = DataEncryption.makeParamStr(StringUtil.encodingHtml(str), "organCode", "UTF-8");
		//			System.out.println(encode);
		//			System.out.println("-> " + StringUtil.decodingHtml(DataEncryption.getParameter(encode, "organCode", "UTF-8")));
		//		} catch (final Exception e) {
		//			Log.error(e.getMessage());
		//		}
	}
}
